﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace PyroGen
{
    public struct Snippet
    {
        public readonly string Text;
        public readonly CodeType Type;


        public Snippet(string text, CodeType type)
        {
            Text = text;
            Type = type;
        }
    }


    public class MalformedStructureException : Exception
    {
        public MalformedStructureException(string msg)
            : base(msg)
        { }
    }


    public class Slicer : PositionFinder
    {
        private readonly List<Snippet> _snippets;


        public Slicer(string text, Dictionary<String, Tuple<CodeType, Terminator>> description) : base(text)
        {
            _snippets = new List<Snippet>();
            AddAllPositions(description);
        }



        private void AssertStructure()
        {
            if(BorderPositions.Count%2 != 0)
                throw new MalformedStructureException("Some tags dont have closures.");
            if(String.IsNullOrEmpty(ProtoText))
                throw new MalformedStructureException("The supplied text is empty or null.");

            for (int i = 1; i + 1 < BorderPositions.Count; i += 2)
            {
                if(BorderPositions[i].Type != BorderPositions[i + 1].Type)
                    throw new MalformedStructureException("Malformed template code! \n"
                +"No ending parenthesis for an open parenthesis.\n Possible ilegal interleaving of opening and closing pharenthesis (ex <. <.= .> ).");
                if(BorderPositions[i].Type == CodeType.Text)
                    throw new MalformedStructureException("Found wrong code type (text) where control keyword should be!");
            }
        }

        private void SliceToPositions()
        {
            AssertStructure();

            Position last = BorderPositions[0];

            for (int i = 1; i + 1 < BorderPositions.Count; i += 2)
            {
                string text = ProtoText.Substring(last.End, BorderPositions[i].Start - last.End);

                //Debug.WriteLine("Added text snippet: \'" + text+"\'");
                _snippets.Add(new Snippet(text, CodeType.Text));


                int currEnd = BorderPositions[i].End;
                int nextStart = BorderPositions[i + 1].Start;
                string code = ProtoText.Substring(currEnd, nextStart - currEnd);

                //Debug.WriteLine("Added " + BorderPositions[i].Type + " snippet: \'"+ code +"\'");
                _snippets.Add(new Snippet(code, BorderPositions[i].Type));
                last = BorderPositions[i + 1];
            }

            int prevLastEnd = last.Location + last.Length;
            string endText = ProtoText.Substring(prevLastEnd,
                                                 BorderPositions[BorderPositions.Count - 1].Start - prevLastEnd);
            //Debug.WriteLine("Added endtext: \'" + endText + "\'");
            _snippets.Add(new Snippet(endText, CodeType.Text));
        }

        public AbstractCode GetAbstractCode()
        {
            SliceToPositions();
            return new AbstractCode(_snippets);
        }

        public List<Snippet> GetSlicedSource()
        {
            SliceToPositions();
            return _snippets;
        }
    }
}